﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using SofireXSqlEntityGenerator.Core;

namespace SofireXSqlEntityGenerator
{
    public interface ITemplate
    {
        string GetValue(string templateName);
    }
    public class XSqlTemplateOpionts : ITemplate
    {
        private string _TableName;
        public string TableName
        {
            get
            {
                return this._TableName;
            }
            set
            {
                this._TableName = value;
            }
        }
        public List<TemplateItem> Items { get; set; }
        public SqlGeneratorBase Generator { get; set; }

        private SqlOptions SqlOptions;
        private string GetString(SqlOperator @operator)
        {
            if(SqlOptions == null)
            {
                SqlOptions = new SqlOptions(@operator);
                SqlOptions.Columns = new string[Items.Count];
                SqlOptions.TableName = this._TableName;
                int index = 0;
                foreach(var item in Items)
                {
                    SqlOptions.Columns[index++] = item.FieldName;
                }
            }
            else SqlOptions.Operator = @operator;
            return this.Generator.CreateSql(SqlOptions);
        }

        private string _Select;
        public string Select
        {
            get
            {
                if(this._Select == null) this._Select = GetString(SqlOperator.Select);
                return this._Select;
            }
        }

        private string _Insert;
        public string Insert
        {
            get
            {
                if(this._Insert == null) this._Insert = GetString(SqlOperator.Insert);
                return this._Insert;
            }
        }

        private string _Update;
        public string Update
        {
            get
            {
                if(this._Update == null) this._Update = GetString(SqlOperator.Update);
                return this._Update;
            }
        }

        private string _Delete;
        public string Delete
        {
            get
            {
                if(this._Delete == null) this._Delete = GetString(SqlOperator.Delete);
                return this._Delete;
            }
        }

        #region ITemplate 成员

        public string GetValue(string templateName)
        {
            switch(templateName)
            {
                case "Select":
                    return Select;
                case "Insert":
                    return Insert;
                case "Update":
                    return Update;
                case "Delete":
                    return Delete;
            }
            return null;
        }

        #endregion
    }

    public class TemplateOptions : ITemplate
    {
        //public string TableComment { get; set; }
        public string ClassName { get; set; }
        public string Namespace { get; set; }
        public string AliasName { get; set; }

        public List<TemplateItem> Items { get; set; }

        public string ConstFieldTemplates { get; set; }
        public string PropertyTemplates { get; set; }
        public string ModelLoadableItemTemplates { get; set; }
        public string ParameterTemplates { get; set; }

        public string GetValue(string templateName)
        {
            string content;
            switch(templateName)
            {
                //case "TableComment":
                //    if(TableComment == null) return "表示一个 <see cref=\"" + this.Namespace + "." + this.ClassName + "\" /> 数据库实体。";
                //    return TableComment;

                case "AliasName":
                    return AliasName;

                case "ClassName":
                    return ClassName;

                case "Namespace":
                    return Namespace;
                case "ConstFieldTemplates":
                    content = CreateContent(ConstFieldTemplates);
                    break;
                case "PropertyTemplates":
                    content = CreateContent(PropertyTemplates);
                    break;
                case "ModelLoadableItemTemplates":
                    content = CreateContent(ModelLoadableItemTemplates);
                    break;
                case "ParameterTemplates":
                    content = CreateContent(ParameterTemplates);
                    break;
                default:
                    return null;
            }

            StringBuilder builder = new StringBuilder();
            foreach(var item in this.Items)
            {
                Matches(builder, item, content);
            }
            return builder.ToString();
        }

        private static string CreateContent(string templateFileName)
        {
            return File.ReadAllText(Path.Combine(GlobalSetting.TemplatesDirectory, templateFileName), Encoding.UTF8);
        }

        private readonly static Regex BindRegex = new Regex("#{[^}]+}", RegexOptions.Compiled);
        public static string Create(ITemplate options, string classTemplate)
        {
            var content = CreateContent(classTemplate);
            StringBuilder builder = new StringBuilder();
            Matches(builder, options, content);
            return builder.ToString();
        }

        private static void Matches(StringBuilder builder, ITemplate template, string content)
        {
            var textMatches = BindRegex.Matches(content);

            Match lastMatch = null;

            foreach(Match match in textMatches)
            {
                if(lastMatch == null)
                {
                    //- 添加第一个匹配的前的所有文本
                    builder.Append(content.Substring(0, match.Index));
                }
                else
                {
                    var nextIndex = lastMatch.Index + lastMatch.Length;
                    builder.Append(content.Substring(nextIndex, match.Index - nextIndex));
                }
                builder.Append(template.GetValue(match.Value.Substring(2, match.Value.Length - 3)));
                lastMatch = match;
            }
            if(lastMatch != null)
            {
                var nextIndex = lastMatch.Index + lastMatch.Length;
                builder.Append(content.Substring(nextIndex));
            }
        }
    }

    public class TemplateItem : ITemplate
    {

        public TemplateOptions Parent { get; set; }
        public string PropertyName { get; set; }
        public string FieldName { get; set; }
        public string PropertyType { get; set; }
        public string PropertyFullType { get; set; }
        public string Comment { get; set; }


        public string GetValue(string templateName)
        {
            switch(templateName)
            {
                case "PropertyName":
                    return PropertyName;

                case "Comment":
                    if(Comment == null) return "表示一个 <see cref=\"" + this.Parent.Namespace + "." + this.Parent.ClassName + "." + this.PropertyName + "\" /> 数据库字段。";
                    return Comment;

                case "FieldName":
                    return FieldName;

                case "PropertyType":
                    if(PropertyType == Types.Boolean.Name) return "bool";
                    else if(PropertyType == Types.Int16.Name) return "short";
                    else if(PropertyType == Types.Int32.Name) return "int";
                    else if(PropertyType == Types.Int64.Name) return "long";
                    else if(PropertyType == Types.Single.Name) return "float";
                    else if(PropertyType == Types.Double.Name) return "double";
                    else if(PropertyType == Types.Decimal.Name) return "decimal";
                    //else if(PropertyType == Types.DateTime.Name) return "DateTime";
                    else if(PropertyType == Types.String.Name) return "string";
                    else if(PropertyType == Types.ByteArray.Name) return "byte[]";

                    return PropertyType;

                case "PropertyFullType":
                    return PropertyFullType;
            }

            return Parent.GetValue(templateName);
        }
    }
}
